<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
	xmlns:f="livcos.org/ns/xslt/function"
	xmlns:t="livcos.org/ns/cosmos/type"
	exclude-result-prefixes="t f">
	
	<xsl:template name="idPath">
		<xsl:param name="id"/>
		<xsl:text>.</xsl:text>
		<xsl:for-each select="tokenize($id, '\.')">
			<xsl:text>/</xsl:text>
			<xsl:choose>
				<xsl:when test=". = ''">
					<xsl:text>.</xsl:text>
				</xsl:when>
				<xsl:when test="(. = '1') and (position() = 1)">
					<!-- a starting '1' represents the context element (normally the root element) -->
					<xsl:text>.</xsl:text>
				</xsl:when>
				<xsl:when test="starts-with(.,'@xmlns')">
					<!-- ignore for now and address the owner element...
						<xsl:text>/namespace::*[local-name(.) = '</xsl:text>
						<xsl:value-of select="substring($tk, 8)" />
						<xsl:text>']</xsl:text-->
				</xsl:when>
				<xsl:when test="starts-with(.,'@')">
					<xsl:value-of select="." />
				</xsl:when>
				<xsl:when test="matches(.,'^[0-9]+$')">
					<xsl:text>node()[</xsl:text>
					<xsl:value-of select="."/>
					<xsl:text>]</xsl:text>
				</xsl:when>
				<xsl:otherwise>
					<xsl:text>/*[@id = '</xsl:text>
					<xsl:value-of select="." />
					<xsl:text>']</xsl:text>
				</xsl:otherwise>
			</xsl:choose>
		</xsl:for-each>
	</xsl:template>
	
	<xsl:template name="applyNode">
		<xsl:param name="parentNode"/>
		<xsl:param name="id"/>
		<xsl:variable name="tk" select="if (contains($id, '.')) then substring-before($id, '.') else $id"/>
		<xsl:choose>
			<xsl:when test="starts-with($tk,'@xmlns')">
				<!--xsl:message>
					<xsl:value-of select="name($parentNode)"/>|<xsl:value-of select="$tk"/>|<xsl:value-of
					select="name($parentNode/namespace::*[local-name(.) = substring($tk,8)])"/>|<xsl:for-each
					select="$parentNode/namespace::*">
					<xsl:value-of select="local-name()"/>:<xsl:value-of select="."/>|</xsl:for-each>
					</xsl:message-->
				<xsl:variable name="node" select="$parentNode/namespace::*[local-name(.) = substring($tk,8)]"/>
				<xsl:variable name="nsNode">
					<t:namespace prefix="{local-name($node)}"><xsl:value-of select="$node"/></t:namespace>
				</xsl:variable>
				<xsl:apply-templates select="$nsNode" mode="applyNode"/>
			</xsl:when>
			<xsl:when test="starts-with($tk,'@')">
				<xsl:variable name="node" select="$parentNode/@*[name(.) = substring($tk,2)]"/>
				<xsl:apply-templates select="$node" mode="applyNode"/>
				<xsl:if test="not($node)">
					<xsl:call-template name="applyNode_fallback"/>
				</xsl:if>
			</xsl:when>
			<xsl:when test="matches($tk,'^[0-9]+')">
				<!--xsl:message>
					<xsl:value-of select="name($parentNode)"/>[<xsl:value-of select="$tk"/>]: <xsl:value-of select="name($parentNode/node()[number($tk)])"/>
					</xsl:message-->
				<xsl:call-template name="applyNode">
					<xsl:with-param name="parentNode" select="$parentNode/node()[number($tk)]"/>
					<xsl:with-param name="id" select="substring-after($id,'.')"/>
				</xsl:call-template>
			</xsl:when>
			<xsl:when test="$tk != ''">
				<xsl:call-template name="applyNode">
					<xsl:with-param name="parentNode" select="$parentNode//*[@id = $tk]"/>
					<xsl:with-param name="id" select="substring-after($id,'.')"/>
				</xsl:call-template>
			</xsl:when>
			<xsl:otherwise>
				<xsl:apply-templates select="$parentNode" mode="applyNode"/>
				<xsl:if test="not($parentNode)">
					<xsl:call-template name="applyNode_fallback"/>
				</xsl:if>
			</xsl:otherwise>
		</xsl:choose>
	</xsl:template>
	
	<xsl:template name="applyNode_fallback">
	</xsl:template>
	
	<xsl:template match="@*|node()" mode="applyNode">
		<xsl:apply-templates select="."/>
	</xsl:template>
	
	
	<!-- NodeID -->
	
	<xsl:function name="f:childIndex">
		<xsl:param name="node"/>
		<xsl:value-of select="count($node/preceding-sibling::node())+1"/>
	</xsl:function>
	
	<xsl:function name="f:nodeId">
		<xsl:param name="node"/>
		<xsl:apply-templates select="$node" mode="_fn_nodeId"/>
	</xsl:function>
	
	<xsl:template match="node()" mode="_fn_nodeId">
		<xsl:apply-templates select=".." mode="_fn_nodeId"/>
		<xsl:text>.</xsl:text>
		<xsl:value-of select="f:childIndex(.)"/>
	</xsl:template>
	
	<xsl:template match="/*" mode="_fn_nodeId">
		<xsl:text>1</xsl:text>
	</xsl:template>
	
	<xsl:template match="*[@id]" mode="_fn_nodeId" priority="2">
		<xsl:value-of select="@id"/>
	</xsl:template>
	
	<xsl:function name="f:nodeById">
		<xsl:param name="nodeId"/>
		<xsl:param name="context"/>
		<xsl:apply-templates select="$context" mode="_fn_nodeById">
			<xsl:with-param name="nodeId" select="$nodeId"/>
		</xsl:apply-templates>
	</xsl:function>
	
	<xsl:template match="node() | /" mode="_fn_nodeById">
		<xsl:param name="nodeId"/>
		<xsl:variable name="id"
			select="if (contains($nodeId, '.')) then substring-before($nodeId, '.') else $nodeId"/>
		<xsl:choose>
			<xsl:when test="normalize-space($id) = ''">
				<xsl:copy-of select="."/>
			</xsl:when>
			<xsl:when test="starts-with($id,'@xmlns')">
				<xsl:variable name="node" select="namespace::*[local-name(.) = substring($id,8)]"/>
				<t:namespace prefix="{local-name($node)}"><xsl:value-of select="$node"/></t:namespace>
			</xsl:when>
			<xsl:when test="starts-with($id,'@')">
				<xsl:copy-of select="@*[name(.) = substring($id,2)]"/>
			</xsl:when>
			<xsl:when test="matches($id,'^[0-9]+')">
				<xsl:apply-templates select="node()[number($id)]" mode="_fn_nodeById">
					<xsl:with-param name="nodeId" select="substring-after($nodeId, '.')"/>
				</xsl:apply-templates>
			</xsl:when>
			<xsl:otherwise>
				<xsl:apply-templates select=".//*[@id = $id]" mode="_fn_nodeById">
					<xsl:with-param name="nodeId" select="substring-after($nodeId, '.')"/>
				</xsl:apply-templates>
			</xsl:otherwise>
		</xsl:choose>
	</xsl:template>
	
	<xsl:function name="f:xPath">
		<xsl:param name="context" as="node()"/>
		<xsl:param name="node"/>
		<xsl:text>.</xsl:text>
		<xsl:apply-templates select="$node" mode="_fn_xPath">
			<xsl:with-param name="context" select="$context"/>
		</xsl:apply-templates>
	</xsl:function>
	
	<xsl:template match="node()" mode="_fn_xPath">
		<xsl:param name="context" as="node()"/>
		<xsl:if test="not (. is $context)">
			<xsl:apply-templates select=".." mode="_fn_xPath">
				<xsl:with-param name="context" select="$context"/>
			</xsl:apply-templates>
			<xsl:text>/node()[</xsl:text>
			<xsl:value-of select="f:childIndex(.)"/>
			<xsl:text>]</xsl:text>
		</xsl:if>
	</xsl:template>
	
	<xsl:template match="@*" mode="_fn_xPath">
		<xsl:param name="context" as="node()"/>
		<xsl:if test="not (. is $context)">
			<xsl:apply-templates select=".." mode="_fn_xPath">
				<xsl:with-param name="context" select="$context"/>
			</xsl:apply-templates>
			<xsl:text>/@</xsl:text>
			<xsl:value-of select="node-name(.)"/>
		</xsl:if>
	</xsl:template>
	
</xsl:stylesheet>
